#include "MephistoCAM.h"

/*
@2023-11-11: 增加选项use_16bits_output来控制DCDS权重参数的配置
    1)  如果PL端每次向DDR写入的是512bits，则表示写入的是32位浮点数，那么不需要对DCDS权重做修改；
    2)  如果PL端每次向DDR写入的是256bits，则表示写入的是16位无符号整数，但因为ADC是14bits，
        直接在PL端将浮点数转成uint16会导致明显的精度损失，一个便捷解决方法就是将DCDS权重参数乘以4
*/

void test_os_ch_encode(){
    uint32_t os_ch;
    for( os_ch = 0; os_ch < 16; os_ch++ ){
        set_FLOAT_SPI_PS_SET_OS_CH( NULL, os_ch );
    }
}

int main( int argc, char *argv[] ){

    if( argc != 2 ){
        printf("\nusage: %s dcds_weights.ini\n",argv[0]);
        return 0;
    }

    printf("(DCDS) updating DCDS parameters from: %s\n", argv[1]);

    char ini_fname[1024];
    sprintf(ini_fname, "%s", argv[1]);

    dictionary *dict_ini;
    dict_ini = iniparser_load(ini_fname);
    if( dict_ini == NULL ){
        fprintf(stderr, "cannot parse file: %s\n", ini_fname);
        return 0;
    }

    float scale = 1.0;
    int use_16bits_output = iniparser_getint(dict_ini, "DCDS_WEIGHTS:use_16bits_output", 0);
    if( use_16bits_output == 1 ){
        scale = 4.0;
    }

//  =================================================================================
//  prepare DCDS weights data
    uint32_t w_size = iniparser_getint(dict_ini, "DCDS_WEIGHTS:w_size", 10);
    // printf("##> DCDS weight size : %d\n", w_size);

    float regs_w_float[16];
    uint32_t *regs_w_uint[16];

    uint32_t os_ch;

    // allocate memory for DCDS weights
    for( os_ch = 0; os_ch < 16; os_ch++ ){
        regs_w_uint[os_ch]  = malloc(sizeof(uint32_t)*w_size);
    }

    char *wfile = (char*)iniparser_getstring(dict_ini, "DCDS_WEIGHTS:w_file", NULL);

    if( wfile != NULL ){
        FILE *fp = fopen(wfile, "r");

        uint32_t w_cnt = 0;

        while( fscanf(fp, "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
                        &regs_w_float[0],
                        &regs_w_float[1],
                        &regs_w_float[2],
                        &regs_w_float[3],
                        &regs_w_float[4],
                        &regs_w_float[5],
                        &regs_w_float[6],
                        &regs_w_float[7],
                        &regs_w_float[8],
                        &regs_w_float[9],
                        &regs_w_float[10],
                        &regs_w_float[11],
                        &regs_w_float[12],
                        &regs_w_float[13],
                        &regs_w_float[14],
                        &regs_w_float[15] ) == 16 ){

            for( os_ch = 0; os_ch < 16; os_ch++ ){
                getFloatBin_uint32(regs_w_float[os_ch]*scale, &regs_w_uint[os_ch][w_cnt]);
            }

            w_cnt++;
        }

        // printf("#==> DCDS_W_SIZE = %d\n", w_cnt);

        if( w_cnt != w_size ){
            char errmsg[1024];
            sprintf(errmsg, "w_cnt != w_size");
            printDebugInfo(errmsg);
            exit(0);
        }

        fclose(fp);
    } else {
        char errmsg[2048];
        sprintf(errmsg, "failed to get w_file from:%s", ini_fname);
        printDebugInfo(errmsg);
        exit(0);
    }


//  Send data to PL side:
    int fd = open("/dev/mem", O_RDWR | O_SYNC);

    uint *fptr = mmap(NULL, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, ADDR_Float_Point_CTRL);
    uint *GPIO_FP_CTRL = fptr;      // 0x41220000
    uint *GPIO_FP_DATA = fptr + 2;  // 0x41220008

    for( os_ch = 0; os_ch < 16; os_ch++ ){
        Config_DCDS_Weights( GPIO_FP_CTRL,
                             GPIO_FP_DATA,
                             w_size,
                             os_ch,
                             regs_w_uint[os_ch] );
    }

    munmap(fptr,10);

    close(fd);

    for( os_ch = 0; os_ch < 16; os_ch++ ){
        free(regs_w_uint[os_ch]);
    }

    return 0;
}
